<template>
   <div v-show="isSelected" class="workspace-query-tab column col-12 columns col-gapless no-outline p-0">
      <div class="workspace-query-runner column col-12">
         <div class="workspace-query-runner-footer">
            <div class="workspace-query-buttons">
               <div class="dropdown">
                  <div class="btn-group">
                     <button
                        class="btn btn-dark btn-sm mr-0 pr-1"
                        :class="{'loading':isQuering}"
                        :title="`${t('general.refresh')}`"
                        @click="reloadTable"
                     >
                        <BaseIcon
                           v-if="!+autorefreshTimer"
                           class="mr-1"
                           icon-name="mdiRefresh"
                           :size="24"
                        />
                        <BaseIcon
                           v-else
                           class="mr-1"
                           icon-name="mdiHistory"
                           flip="horizontal"
                           :size="24"
                        />
                     </button>
                     <div class="btn btn-dark btn-sm dropdown-toggle pl-0 pr-0" tabindex="0">
                        <BaseIcon icon-name="mdiMenuDown" :size="24" />
                     </div>
                     <div class="menu px-3">
                        <span>{{ t('general.autoRefresh') }}: <b>{{ +autorefreshTimer ? `${autorefreshTimer}s` : 'OFF' }}</b></span>
                        <input
                           v-model="autorefreshTimer"
                           class="slider no-border"
                           type="range"
                           min="0"
                           max="30"
                           step="1"
                           @change="setRefreshInterval"
                        >
                     </div>
                  </div>
               </div>
               <div class="btn-group">
                  <button
                     class="btn btn-dark btn-sm mr-0"
                     :disabled="isQuering || page === 1"
                     :title="t('application.previousResultsPage')"
                     @click="pageChange('prev')"
                  >
                     <BaseIcon icon-name="mdiSkipPrevious" :size="24" />
                  </button>
                  <div class="dropdown" :class="{'active': isPageMenu}">
                     <div @click="openPageMenu">
                        <div class="btn btn-dark btn-sm mr-0 no-radius dropdown-toggle text-bold px-3">
                           {{ page }}
                        </div>
                        <div class="menu px-3">
                           <span>{{ t('general.pageNumber') }}</span>
                           <input
                              ref="pageSelect"
                              v-model="pageProxy"
                              type="number"
                              min="1"
                              class="form-input"
                              @blur="setPageNumber"
                           >
                        </div>
                     </div>
                  </div>
                  <button
                     class="btn btn-dark btn-sm mr-0"
                     :disabled="isQuering || (results.length && results[0].rows.length < limit)"
                     :title="t('application.nextResultsPage')"
                     @click="pageChange('next')"
                  >
                     <BaseIcon icon-name="mdiSkipNext" :size="24" />
                  </button>
               </div>

               <div class="divider-vert py-3" />

               <button
                  class="btn btn-sm"
                  :title="t('general.filter')"
                  :disabled="isQuering"
                  :class="{'btn-primary': isSearch, 'btn-dark': !isSearch}"
                  @click="isSearch = !isSearch"
               >
                  <BaseIcon icon-name="mdiMagnify" :size="24" />
               </button>
               <button
                  v-if="isTable && !connection.readonly"
                  class="btn btn-dark btn-sm"
                  :disabled="isQuering"
                  @click="showFakerModal()"
               >
                  <BaseIcon
                     icon-name="mdiPlaylistPlus"
                     class="mr-1"
                     :size="24"
                  />
                  <span>{{ t('database.insertRow', 2) }}</span>
               </button>

               <div class="dropdown table-dropdown">
                  <button
                     :disabled="isQuering"
                     class="btn btn-dark btn-sm dropdown-toggle mr-0 pr-0"
                     tabindex="0"
                  >
                     <BaseIcon
                        icon-name="mdiFileExport"
                        class="mr-1"
                        :size="24"
                     />
                     <span>{{ t('database.export') }}</span>
                     <BaseIcon icon-name="mdiMenuDown" :size="24" />
                  </button>
                  <ul class="menu text-left">
                     <li class="menu-item">
                        <a class="c-hand" @click="downloadTable('json')">JSON</a>
                     </li>
                     <li class="menu-item">
                        <a class="c-hand" @click="downloadTable('csv')">CSV</a>
                     </li>
                     <li class="menu-item">
                        <a class="c-hand" @click="downloadTable('php')">{{ t('application.phpArray') }}</a>
                     </li>
                     <li class="menu-item">
                        <a class="c-hand" @click="downloadTable('sql')">SQL INSERT</a>
                     </li>
                  </ul>
               </div>

               <div class="divider-vert py-3" />

               <button
                  class="btn btn-dark btn-sm"
                  :disabled="isQuering"
                  :title="t('application.settings')"
                  @click="openTableSettingTab()"
               >
                  <BaseIcon icon-name="mdiCog" :size="24" />
                  <!-- <span>{{ t('application.settings') }}</span> -->
               </button>
            </div>
            <div class="workspace-query-info">
               <div
                  v-if="results.length"
                  class="d-flex"
                  :title="t('database.queryDuration')"
               >
                  <BaseIcon
                     class="mr-1 mt-1"
                     icon-name="mdiTimerSand"
                     :rotate="180"
                     :size="16"
                  /> <b>{{ results[0].duration / 1000 }}s</b>
               </div>
               <div v-if="results.length && results[0].rows">
                  {{ t('general.results') }}: <b>{{ localeString(results[0].rows.length) }}</b>
               </div>
               <div v-if="hasApproximately || (page > 1 && approximateCount)">
                  {{ t('database.total') }}: <b
                     :title="!customizations.tableRealCount ? t('database.approximately') : ''"
                  >
                     <span v-if="!customizations.tableRealCount">≈</span>
                     {{ localeString(approximateCount) }}
                  </b>
               </div>
               <div class="d-flex" :title="t('database.schema')">
                  <BaseIcon
                     class="mt-1 mr-1"
                     icon-name="mdiDatabase"
                     :size="18"
                  /><b>{{ schema }}</b>
               </div>
            </div>
         </div>
      </div>
      <WorkspaceTabTableFilters
         v-if="isSearch"
         :fields="fields"
         :is-quering="isQuering"
         :conn-client="connection.client"
         @filter="updateFilters"
         @filter-change="onFilterChange"
      />
      <div class="workspace-query-results p-relative column col-12">
         <BaseLoader v-if="isQuering" />
         <div v-if="!isQuering && !results[0]?.rows.length" class="empty">
            <div class="empty-icon">
               <BaseIcon icon-name="mdiIsland" :size="56" />
            </div>
            <p class="h4 empty-subtitle">
               {{ t('database.noResultsPresent') }}
            </p>
         </div>
         <WorkspaceTabQueryTable
            v-if="results"
            ref="queryTable"
            :results="results"
            :is-quering="isQuering"
            :page="page"
            :tab-uid="tabUid"
            :conn-uid="connection.uid"
            :is-selected="isSelected"
            mode="table"
            :element-type="elementType"
            @update-field="updateField"
            @delete-selected="deleteSelected"
            @duplicate-row="showFakerModal"
            @hard-sort="hardSort"
         />
      </div>
      <ModalFakerRows
         v-if="isFakerModal"
         :fields="fields"
         :row-to-duplicate="rowToDuplicate"
         :key-usage="keyUsage"
         :tab-uid="tabUid"
         :schema="schema"
         :table="table"
         @hide="hideFakerModal"
         @reload="reloadTable"
      />
   </div>
</template>

<script setup lang="ts">
import { ConnectionParams } from 'common/interfaces/antares';
import { TableFilterClausole } from 'common/interfaces/tableApis';
import { ipcRenderer } from 'electron';
import { storeToRefs } from 'pinia';
import { computed, nextTick, onBeforeUnmount, Prop, Ref, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';

import BaseIcon from '@/components/BaseIcon.vue';
import BaseLoader from '@/components/BaseLoader.vue';
import ModalFakerRows from '@/components/ModalFakerRows.vue';
import WorkspaceTabQueryTable from '@/components/WorkspaceTabQueryTable.vue';
import WorkspaceTabTableFilters from '@/components/WorkspaceTabTableFilters.vue';
import { useFilters } from '@/composables/useFilters';
import { useResultTables } from '@/composables/useResultTables';
import Tables from '@/ipc-api/Tables';
import { useNotificationsStore } from '@/stores/notifications';
import { useSettingsStore } from '@/stores/settings';
import { useWorkspacesStore } from '@/stores/workspaces';

const { localeString } = useFilters();

const { t } = useI18n();

const props = defineProps({
   connection: Object as Prop<ConnectionParams>,
   isSelected: Boolean,
   table: String,
   schema: String,
   elementType: String
});

const reloadTable = async () => {
   await nextTick();
   getTableData();
};

const {
   queryTable,
   isQuering,
   updateField,
   deleteSelected
} = useResultTables(props.connection.uid, reloadTable);

const { addNotification } = useNotificationsStore();
const settingsStore = useSettingsStore();
const workspacesStore = useWorkspacesStore();

const { dataTabLimit: limit } = storeToRefs(settingsStore);

const { changeBreadcrumbs, getWorkspace, newTab } = workspacesStore;

const pageSelect: Ref<HTMLInputElement> = ref(null);
const tabUid = ref('data');
const isPageMenu = ref(false);
const isSearch = ref(false);
const results = ref([]);
const lastTable = ref(null);
const isFakerModal = ref(false);
const autorefreshTimer = ref(0);
const refreshInterval = ref(null);
const sortParams = ref({} as { field: string; dir: 'asc' | 'desc'});
const filters = ref([]);
const page = ref(1);
const pageProxy = ref(1);
const approximateCount = ref(0);
const rowToDuplicate = ref(null);

const workspace = computed(() => {
   return getWorkspace(props.connection.uid);
});

const customizations = computed(() => {
   return workspace.value.customizations;
});

const isTable = computed(() => {
   return props.elementType === 'table';
});

const fields = computed(() => {
   return results.value.length ? results.value[0].fields : [];
});

const keyUsage = computed(() => {
   return results.value.length ? results.value[0].keys : [];
});

const getTableData = async () => {
   if (!props.table || !props.isSelected || isQuering.value) return;
   isQuering.value = true;

   // if table changes clear cached values
   if (lastTable.value !== props.table)
      results.value = [];

   lastTable.value = props.table;

   const params = {
      uid: props.connection.uid,
      schema: props.schema,
      table: props.table,
      limit: limit.value,
      page: page.value,
      sortParams: { ...sortParams.value },
      where: [...filters.value] || []
   };

   try { // Table data
      const { status, response } = await Tables.getTableData(params);

      if (status === 'success')
         results.value = [response];
      else
         addNotification({ status: 'error', message: response });
   }
   catch (err) {
      addNotification({ status: 'error', message: err.stack });
   }

   if (results.value.length && results.value[0].rows.length === limit.value) {
      try { // Table approximate count
         const { status, response } = await Tables.getTableApproximateCount(params);

         if (status === 'success')
            approximateCount.value = response;
         else
            addNotification({ status: 'error', message: response as unknown as string });
      }
      catch (err) {
         addNotification({ status: 'error', message: err.stack });
      }
   }

   isQuering.value = false;
};

const hardSort = (params: { field: string; dir: 'asc' | 'desc'}) => {
   sortParams.value = params;
   getTableData();
};

const openPageMenu = () => {
   if (isQuering.value || (results.value.length && results.value[0].rows.length < limit.value && page.value === 1)) return;

   isPageMenu.value = true;
   if (isPageMenu.value)
      setTimeout(() => pageSelect.value.focus(), 20);
};

const setPageNumber = () => {
   isPageMenu.value = false;

   if (pageProxy.value > 0)
      page.value = pageProxy.value;
   else
      pageProxy.value = page.value;
};

const pageChange = (direction: 'prev' | 'next') => {
   if (isQuering.value) return;

   if (direction === 'next' && (results.value.length && results.value[0].rows.length === limit.value)) {
      if (!page.value)
         page.value = 2;
      else
         page.value++;
   }
   else if (direction === 'prev' && page.value > 1)
      page.value--;
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const showFakerModal = (row?: any) => {
   if (isQuering.value) return;
   isFakerModal.value = true;
   rowToDuplicate.value = row;
};

const hideFakerModal = () => {
   isFakerModal.value = false;
   rowToDuplicate.value = null;
};

const setRefreshInterval = () => {
   if (refreshInterval.value)
      clearInterval(refreshInterval.value);

   if (+autorefreshTimer.value) {
      refreshInterval.value = setInterval(() => {
         if (!isQuering.value)
            reloadTable();
      }, autorefreshTimer.value * 1000);
   }
};

const downloadTable = (format: 'csv' | 'json' | 'sql' | 'php') => {
   queryTable.value.downloadTable(format, props.table);
};

const onFilterChange = (clausoles: TableFilterClausole[]) => {
   resizeScroller();
   if (clausoles.length === 0)
      isSearch.value = false;
};

const resizeScroller = () => {
   setTimeout(() => queryTable.value.refreshScroller(), 1);
};

const updateFilters = (clausoles: TableFilterClausole[]) => {
   filters.value = clausoles;
   results.value = [];

   const permanentTabs = {
      table: 'data',
      view: 'data',
      trigger: 'trigger-props',
      triggerFunction: 'trigger-function-props',
      function: 'function-props',
      routine: 'routine-props',
      procedure: 'routine-props',
      scheduler: 'scheduler-props'
   } as Record<string, string>;

   newTab({
      uid: props.connection.uid,
      schema: props.schema,
      elementName: props.table,
      type: permanentTabs[props.elementType],
      elementType: props.elementType
   });
   getTableData();
};

const reloadListener = () => {
   const hasModalOpen = !!document.querySelectorAll('.modal.active').length;
   if (props.isSelected && !hasModalOpen)
      reloadTable();
};

const openFilterListener = () => {
   const hasModalOpen = !!document.querySelectorAll('.modal.active').length;
   if (props.isSelected && !hasModalOpen)
      isSearch.value = !isSearch.value;
};

const nextPageListener = () => {
   const hasModalOpen = !!document.querySelectorAll('.modal.active').length;
   if (props.isSelected && !hasModalOpen)
      pageChange('next');
};

const prevPageListener = () => {
   const hasModalOpen = !!document.querySelectorAll('.modal.active').length;
   if (props.isSelected && !hasModalOpen)
      pageChange('prev');
};

const hasApproximately = computed(() => {
   return results.value.length &&
      results.value[0].rows &&
      results.value[0].rows.length === limit.value &&
      results.value[0].rows.length < approximateCount.value;
});

const openTableSettingTab = () => {
   newTab({
      uid: workspace.value.uid,
      elementName: props.table,
      schema: props.schema,
      type: isTable.value ? 'table-props' : props.elementType === 'view' ? 'view-props' : 'materialized-view-props',
      elementType: props.elementType
   });

   changeBreadcrumbs({
      schema: props.schema,
      table: isTable.value ? props.table : null,
      view: !isTable.value ? props.table : null
   });
};

watch(() => props.schema, () => {
   if (props.isSelected) {
      page.value = 1;
      approximateCount.value = 0;
      sortParams.value = {} as { field: string; dir: 'asc' | 'desc'};
      getTableData();
      lastTable.value = props.table;
      queryTable.value.resetSort();
   }
});

watch(() => props.table, () => {
   if (props.isSelected) {
      page.value = 1;
      filters.value = [];
      isSearch.value = false;
      approximateCount.value = 0;
      sortParams.value = {} as { field: string; dir: 'asc' | 'desc'};
      getTableData();
      lastTable.value = props.table;
      queryTable.value.resetSort();
   }
});

watch(page, (val, oldVal) => {
   if (val && val > 0 && val !== oldVal) {
      pageProxy.value = page.value;
      getTableData();
   }
});

watch(() => props.isSelected, (val) => {
   if (val) {
      changeBreadcrumbs({ schema: props.schema, [props.elementType]: props.table });

      if (lastTable.value !== props.table)
         getTableData();
   }
});

watch(isSearch, (val) => {
   if (filters.value.length > 0 && !val) {
      filters.value = [];
      getTableData();
   }
   resizeScroller();
});

getTableData();

ipcRenderer.on('run-or-reload', reloadListener);
ipcRenderer.on('open-filter', openFilterListener);
ipcRenderer.on('next-page', nextPageListener);
ipcRenderer.on('prev-page', prevPageListener);

onBeforeUnmount(() => {
   clearInterval(refreshInterval.value);
   ipcRenderer.removeListener('run-or-reload', reloadListener);
   ipcRenderer.removeListener('open-filter', openFilterListener);
   ipcRenderer.removeListener('next-page', nextPageListener);
   ipcRenderer.removeListener('prev-page', prevPageListener);
});
</script>
